/**
  ******************************************************************************
  * @file           : certificateManager.cpp
  * @author         : sally
  * @brief          : None
  * @attention      : None
  * @date           : 24-12-18
  ******************************************************************************
  */

#include "certificateManager.h"
#include <cstddef>
#include <cstdio>
#include <cstdlib>
#include <fcntl.h>
#include <fstream>
#include <iostream>
#include <iterator>
#include <openssl/asn1.h>
#include <openssl/bio.h>
#include <openssl/bn.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/pem.h>
#include <openssl/types.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include <sys/stat.h>
#include <sys/time.h>

#include "TimeOperation.h"

BIGNUM* generate_large_serial_number()
{
    BIGNUM* bn = BN_new();
    if (!bn) {
        std::cerr << "Failed to create BIGNUM." << std::endl;
        return nullptr;
    }

    if (!BN_rand(bn, 128, 0, 0)) {
        std::cerr << "Failed to generate random number." << std::endl;
        BN_free(bn);
        return nullptr;
    }
    return bn;
}

CertificateManager::CertificateManager() {}

bool CertificateManager::X509_REQ_to_DER(X509_REQ* req, std::vector<unsigned char>& der_data)
{
    int len = i2d_X509_REQ(req, nullptr);
    if (len < 0) {
        std::cerr << "Failed to get DER length" << std::endl;
        return false;
    }

    der_data.resize(len);

    unsigned char* ptr = der_data.data();
    if (!i2d_X509_REQ(req, &ptr)) {
        std::cerr << "Failed to convert X509_REQ to DER" << std::endl;
        return false;
    }

    return true;
}

bool CertificateManager::loadCACertificate(EVP_PKEY** CA_pubKey, const std::string& certificatePath)
{
    // FILE* file = fopen(certificatePath.c_str(), "rb");
    // if (!file) {
    //     // std::cout << "108" << std::endl;
    //     std::cerr << "Unable to open CACertificate file: " << certificatePath << std::endl;
    //     return false;
    // }
    BIO* b = BIO_new_file(certificatePath.c_str(), "r");
    if (!b) {
        std::cerr << "Unable to open CACertificate file: " << certificatePath << std::endl;
        return false;
    }

    X509* caCert = PEM_read_bio_X509(b, nullptr, nullptr, nullptr);
    BIO_free(b);
    // X509* caCert = PEM_read_X509(file, NULL, NULL, NULL);
    // fclose(file);

    if (!caCert) {
        // std::cout << "115" << std::endl;
        std::cerr << "Failed to load certificate from: " << certificatePath << std::endl;
        /* ERR_print_errors_fp(stderr);*/ // 输出错误信息到标准错误
        return false;
    }

    // fclose(file);

    // 从证书中读取公钥
    EVP_PKEY* CaPubKey = X509_get_pubkey(caCert);
    if (!CaPubKey) {
        // std::cout << "126" << std::endl;
        // handleOpenSSLErrors();
        X509_free(caCert);
        return false;
    }

    *CA_pubKey = CaPubKey;

    X509_free(caCert);
    return true;
}

CertificateManager::~CertificateManager() {}

X509_REQ* CertificateManager::generateCSR(const std::map<std::string, std::string>& subjectInfo,
                                          EVP_PKEY* userKey)
{
    if (!userKey) {
        std::cerr << "userKey is nullptr!" << std::endl;
        return nullptr;
    }

    X509_REQ* req = X509_REQ_new();
    if (!req) {
        return NULL;
    }

    // 设置版本号
    X509_REQ_set_version(req, 0);

    // 设置CSR的主体信息
    X509_NAME* name = X509_NAME_new();

    for (const auto& field : subjectInfo) {
        X509_NAME_add_entry_by_txt(name,
                                   field.first.c_str(),
                                   MBSTRING_ASC,
                                   (const unsigned char*) field.second.c_str(),
                                   -1,
                                   -1,
                                   -1);
    }
    X509_REQ_set_subject_name(req, name);
    X509_NAME_free(name);

    // 还需要设置X509_PUBKEY *pubkey;

    if (X509_REQ_set_pubkey(req, userKey) != 1) {
        std::cerr << "Failed to set public key!" << std::endl;
        X509_REQ_free(req);
        return NULL;
    }
    // 需要使用私钥来对CSR进行签名，来确保CSR的不可抵赖性和完整性
    if (!X509_REQ_sign(req, userKey, EVP_sha256())) {
        perror("X509_REQ_sign");
        X509_REQ_free(req);
        return NULL;
    }
    /*
        X509_REQ_sign( req, userKey, EVP_sha256() )函数同时也是将使用的签名算法填充到X509_ALGOR *sig_alg;字段中
        用于说明签名时使用了什么算法。它告诉了验证者应该使用何种算法来验证签名的有效性。
    */
    return req;
}

bool CertificateManager::saveCertificate(X509* cert, const std::string& filePath)
{
    // 首先需要检查这个证书是否为nullptr
    if (!cert) {
        perror("cert");
        return false;
    }

    BIO* bio = BIO_new_file(filePath.c_str(), "w");
    if (!bio) {
        OPERATION_FAIL("BIO_new_file", "CertificateManager", __FILE__, __LINE__, "");
        return false;
    }

    // 写入证书
    if (!PEM_write_bio_X509(bio, cert)) {
        OPERATION_FAIL("BIO_new_file", "CertificateManager", __FILE__, __LINE__, "");
        BIO_free(bio);
        return false;
    }
    // 关闭文件
    BIO_free(bio);
    OPERATION_SUCCESS("save Certificate To File" + filePath, "CertificateManager", "");
    return true;
}

bool CertificateManager::savePrivateKey(EVP_PKEY* pkey, const std::string& filePath)
{
    // 首先判断pkey是否为空
    if (!pkey) {
        perror("pkey");
        return false;
    }

    BIO* bio = BIO_new_file(filePath.c_str(), "w");
    if (!bio) {
        OPERATION_FAIL("BIO_new_file", "CertificateManager", __FILE__, __LINE__, "");
        return false;
    }

    // 写入文件
    if (!PEM_write_bio_PrivateKey(bio, pkey, nullptr, nullptr, 0, nullptr, nullptr)) {
        OPERATION_FAIL("PEM_write_bio_PrivateKey", "CertificateManager", __FILE__, __LINE__, "");
        BIO_free(bio);
        return false;
    }

    BIO_free(bio);
    OPERATION_SUCCESS("save Private key to File " + filePath, "RTA", "");
    return true;
}

bool CertificateManager::safeSavePrivateKey(EVP_PKEY* pkey,
                                            const std::string& filePath,
                                            const std::string& passwd)
{
    if (!pkey) {
        perror("pkey");
        return false;
    }

    if (passwd.empty()) {
        OPERATION_FAIL("Password is empty", "CertificateManager", __FILE__, __LINE__, "");
        return false;
    }

    BIO* b = BIO_new_file(filePath.c_str(), "w");
    if (!b) {
        OPERATION_FAIL("BIO_new_file", "CertificateManager", __FILE__, __LINE__, "");
        return false;
    }

    if (!PEM_write_bio_PrivateKey(b,
                                  pkey,
                                  EVP_aes_256_cbc(),
                                  reinterpret_cast<const unsigned char*>(passwd.c_str()),
                                  static_cast<int>(passwd.size()),
                                  nullptr,
                                  nullptr)) {
        OPERATION_FAIL("PEM_write_bio_PrivateKey", "CertificateManager", __FILE__, __LINE__, "");
        BIO_free(b);
        return false;
    }
    BIO_free(b);
    OPERATION_SUCCESS("Encrypted private key save to " + filePath, "RTA", "");
    return true;
}

bool CertificateManager::verifyCert(X509* PeerCert, EVP_PKEY** PeerPubkey, EVP_PKEY* RTA_PubKey)
{
    if (!PeerCert || !PeerPubkey) {
        OPERATION_FAIL("Invalid input: PeerCert or PeerPubkey is nullptr",
                       "CertificateManager",
                       __FILE__,
                       __LINE__,
                       "");
        // handleOpenSSLErrors();
        return false;
    }

    EVP_PKEY* PeerPub = X509_get_pubkey(PeerCert);
    if (!PeerPub) {
        OPERATION_FAIL("PeerPub is nullptr", "CertificateManager", __FILE__, __LINE__, "");
        return false;
    }

    if (X509_verify(PeerCert, RTA_PubKey) != 1) {
        OPERATION_FAIL("X509_verify", "CertificateManager", __FILE__, __LINE__, "");
        EVP_PKEY_free(PeerPub);
        return false;
    }
    *PeerPubkey = PeerPub;
    return true;
}

bool CertificateManager::Extract_and_verify_privKey_is_valid(EVP_PKEY** evp_pri,
                                                             const std::string& privateKeyPath)
{
    // 首先判断这个文件有没有内容，可以使用stat函数
    struct stat statBuf;

    if (stat(privateKeyPath.c_str(), &statBuf) < 0) {
        std::cerr << privateKeyPath << "file not found" << std::endl;
        return false;
    }

    // 判断文件中是否有内容
    if (statBuf.st_size == 0) {
        // 说明文件里面是空的
        std::cerr << privateKeyPath << "The file content is empty" << std::endl;
        return false;
    }
    // 有内容，则验证私钥文件格式是否正确，打开文件

    BIO* bio = BIO_new_file(privateKeyPath.c_str(), "r");
    if (!bio) {
        OPERATION_FAIL("BIO_new_file", "CertificateManager", __FILE__, __LINE__, "");
        return false;
    }

    EVP_PKEY* PriKey = PEM_read_bio_PrivateKey(bio, nullptr, nullptr, nullptr);
    if (!PriKey) {
        OPERATION_FAIL("PEM_read_bio_PrivateKey", "CertificateManager", __FILE__, __LINE__, "");

        return false;
    }
    BIO_free(bio);
    // 验证私钥是否成功读取
    if (EVP_PKEY_base_id(PriKey) == EVP_PKEY_EC) {
        std::cout << "The private key is an EC key." << std::endl;
        *evp_pri = PriKey;
        return true;
    } else if (EVP_PKEY_base_id(PriKey) == EVP_PKEY_RSA) {
        std::cout << "The private key is an RSA key." << std::endl;
        *evp_pri = PriKey;
        return true;
    } else {
        std::cerr << "Unknown private key type." << std::endl;
        EVP_PKEY_free(PriKey);
        return false;
    }
}

bool CertificateManager::ExtractVerifyPKCertIsValid(EVP_PKEY** evp_pubKey,
                                                    const std::string& privateKeyPath)
{
    BIO* bio = BIO_new_file(privateKeyPath.c_str(), "r");
    if (!bio) {
        OPERATION_FAIL("BIO_new_file", "CertificateManager", __FILE__, __LINE__, "");
        return false;
    }

    X509* cert = PEM_read_bio_X509(bio, nullptr, nullptr, nullptr);
    if (!cert) {
        std::cerr << "Unable to load certificate!" << std::endl;
        BIO_free(bio);
        return false;
    }
    BIO_free(bio);
    std::shared_ptr<X509> cert_ptr(cert, X509_Deleter);
    //获取证书的有效期开始时间
    const ASN1_TIME* notBefore = X509_get0_notBefore(cert);
    if (!notBefore) {
        std::cerr << "No 'Not Before' date in certificate!" << std::endl;
        return false;
    }
    const ASN1_TIME* notAfter = X509_get0_notAfter(cert);
    if (!notAfter) {
        std::cerr << "No 'Not After' date in certificate!" << std::endl;
        return false;
    }

    time_t current_time = time(nullptr);
    //这是创建ASN1_TIME类型的指针
    ASN1_TIME* current_asn1_time = ASN1_TIME_new();
    if (!current_asn1_time) {
        std::cerr << "Error creating ASN1_TIME object for current time!" << std::endl;
        return false;
    }

    ASN1_TIME_set(current_asn1_time, current_time);
    int day_diff = 0, sec_diff = 0;
    int result = ASN1_TIME_diff(&day_diff, &sec_diff, current_asn1_time, notAfter);
    ASN1_TIME_free(current_asn1_time);
    //notAfter - current_asn1_time
    if (day_diff < 0 || (day_diff == 0 && sec_diff < 0)) {
        std::cerr << "The certificate has timed out" << std::endl;
        return false;
    }

    //提取公钥
    EVP_PKEY* pubKey = X509_get_pubkey(cert);
    if (!pubKey) {
        std::cerr << "Failed to get pubkey!" << std::endl;
        return false;
    }

    *evp_pubKey = pubKey;
    return true;
}

std::string CertificateManager::readPemFile(const std::string& filePath)
{
    std::ifstream file(filePath);
    if (!file) {
        perror("file");
        return "";
    }
    std::string pemContent((std::istreambuf_iterator<char>(file)), std::istreambuf_iterator<char>());
    file.close();
    return pemContent;
}

X509* CertificateManager::PemCharToX509(char* buffer, ssize_t bytesRead)
{
    // BIO_new_mem_buf用于从已有的内存缓冲区创建一个 BIO

    // 使用OPENSSL_BIO来处理数据
    BIO* bio_mem = BIO_new_mem_buf(buffer, bytesRead);
    if (!bio_mem) {
        perror("bio_mem");
        // handleOpenSSLErrors();
        return nullptr;
    }

    X509* cert = PEM_read_bio_X509(bio_mem, nullptr, nullptr, nullptr);
    BIO_free(bio_mem);

    if (!cert) {
        std::cerr << "Error reading certificate from memory" << std::endl;
        // handleOpenSSLErrors();
        return nullptr;
    }

    return cert;
}

std::vector<unsigned char> CertificateManager::convertX509ToDER(X509* cert)
{
    if (!cert) {
        OPERATION_FAIL("cert is nullptr", "CertificateManager", __FILE__, __LINE__, "");
        return {};
    }
    unsigned char* derBuffer = nullptr;
    int derLength = i2d_X509(cert, &derBuffer);
    if (derLength <= 0) {
        OPERATION_FAIL("i2d_X509", "CertificateManager", __FILE__, __LINE__, "");
        return {};
    }

    std::vector<unsigned char> derData(derBuffer, derBuffer + derLength);
    OPENSSL_free(derBuffer);

    return derData;
}

X509* CertificateManager::convertDERToX509(const unsigned char* der_data, size_t der_size)
{
    if (!der_data) {
        OPERATION_FAIL("der_data is nullptr", "CertificateManager", __FILE__, __LINE__, "");
        return nullptr;
    }

    X509* cert = d2i_X509(nullptr, &der_data, static_cast<long>(der_size));
    if (!cert) {
        OPERATION_FAIL("Failed to parse DER certificate to X509",
                       "CertificateManager",
                       __FILE__,
                       __LINE__,
                       "");
        return nullptr;
    }

    return cert;
}

EVP_PKEY* CertificateManager::getPubKeyFromCert(X509* cert)
{
    if (!cert) {
        std::cerr << "cert is nullptr" << std::endl;
        return nullptr;
    }

    EVP_PKEY* pubKey = X509_get_pubkey(cert);
    if (!pubKey) {
        std::cerr << "X509_get_pubkey failed to obtain, in the getPubKeyFromCert function line 771"
                  << std::endl;
        return nullptr;
    }
    return pubKey;
}
